package com.mvc.finance.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.stereotype.Service;

import com.mvc.base.service.BaseCompanyManager;
import com.mvc.base.service.SupplierManager;
import com.mvc.business.model.Order;
import com.mvc.business.model.OrderAssociated;
import com.mvc.business.service.OrderAssociatedManager;
import com.mvc.business.service.PurchaseManager;
import com.mvc.finance.model.BankStatement;
import com.mvc.finance.model.BankStatementCharge;
import com.mvc.finance.model.BankStatementItem;
import com.mvc.finance.model.ExpenseApply;
import com.mvc.finance.model.FinancePrivilege;
import com.mvc.framework.dao.HibernateIdUtils;
import com.mvc.framework.dao.HibernateWebUtils;
import com.mvc.framework.model.Auditable;
import com.mvc.framework.model.CommonAuditableEntity;
import com.mvc.framework.util.FrameworkContextUtils;
import com.mvc.framework.util.PageSearch;

@Service
public class BankStatementManager extends BaseCompanyManager<BankStatement, Long> {
	@Autowired
	private BankStatementItemManager	bankStatementItemManager;

	@Autowired
	private BankStatementChargeManager	bankStatementChargeManager;

	@Autowired
	private PurchaseManager	           purchaseManager;

	@Autowired
	private FinancePrivilegeManager	   financePrivilegeManager;

	@Autowired
	private OrderAssociatedManager	   orderAssociatedManager;

	@Autowired
	private SupplierManager	           supplierManager;

	public BankStatement getObject(Integer objectId) {
		BankStatement order = super.getByObjectId(objectId);
		if (order != null) {
			order.setBankStatementItems(bankStatementItemManager.getBankStatementItemsByBankStatementId(order.getObjectId()));
			order.setBankStatementCharges(bankStatementChargeManager.getBankStatementChargesByBankStatementId(objectId, null));
			order.setCompany(companyManager.getByObjectId(order.getCompanyId()));
			order.setSupplier(supplierManager.getByObjectId(order.getSupplierId()));
		}
		return order;
	}

	public void save(BankStatement entity) {
		entity.setTotal(getTotal(entity, entity.getObjectId()));
		if (null == entity.getId()) {
			entity.setCompanyId(supplierManager.getByObjectId(entity.getSupplierId()).getCompanyId());
			Integer oldOrderId = entity.getObjectId();
			entity.setObjectId(HibernateIdUtils.getUnCacheCustomizeId(getHibernateTemplate().getSessionFactory(), "bankStatementNo"));
			bankStatementItemManager.updateBankStatementItemId(oldOrderId, entity.getObjectId());
			bankStatementChargeManager.updateBankStatementChargeId(oldOrderId, entity.getObjectId());
			orderAssociatedManager.updateAssociated(oldOrderId, entity.getObjectId(), OrderAssociated.TYPE_BANK_STATEMENT);
		}
		super.save(entity);
	}

	protected Double getTotal(BankStatement entity, Integer bankStatementId) {
		Double total = 0D;
		if (bankStatementId != null) {
			List<BankStatementItem> orderItems = bankStatementItemManager.getBankStatementItemsByBankStatementId(bankStatementId);
			for (BankStatementItem orderItem : orderItems) {
				total += (orderItem.getQuantity() * orderItem.getUnitPrice());
			}
			List<BankStatementCharge> statementCharges = bankStatementChargeManager.getBankStatementChargesByBankStatementId(
			        bankStatementId, null);
			for (BankStatementCharge charge : statementCharges) {
				if (charge.getType() == BankStatementCharge.TYPE_FEE) {
					total += charge.getAmount();
				} else if (charge.getType() == BankStatementCharge.TYPE_DEBIT) {
					total -= charge.getAmount();
				}
			}
		}
		if (entity.getEarnest() != null) {
			total -= entity.getEarnest();
		}
		return total;
	}

	public List<BankStatement> getPaid() {
		String companyId = financePrivilegeManager.getCompanyIdsByUserId(FrameworkContextUtils.getCurrentUserId(),
		        FinancePrivilege.TYPE_DUES);
		String sql = "select A from " + BankStatement.class.getName() + " A where A.recStatus=? and A.financeStatus=?";
		if (companyId == null) {
			return searchBySql(sql, new Object[] { CommonAuditableEntity.REC_STATUS_VALID, Order.ORDER_FINANCE_STATUS_PAYED });
		} else if (companyId.length() > 0) {
			sql += " and companyId in(" + companyId + ")";
			return searchBySql(sql, new Object[] { CommonAuditableEntity.REC_STATUS_VALID, Order.ORDER_FINANCE_STATUS_PAYED });
		} else {
			return new ArrayList<BankStatement>();
		}
	}

	public List<BankStatement> getUnPay() {
		String companyId = financePrivilegeManager.getCompanyIdsByUserId(FrameworkContextUtils.getCurrentUserId(),
		        FinancePrivilege.TYPE_DUES);
		String sql = "select A from " + BankStatement.class.getName() + " A where A.recStatus=? and A.financeStatus=?";
		if (companyId == null) {
			return searchBySql(sql, new Object[] { CommonAuditableEntity.REC_STATUS_VALID, Order.ORDER_FINANCE_STATUS_UNPAY });
		} else if (companyId.length() > 0) {
			sql += " and companyId in(" + companyId + ")";
			return searchBySql(sql, new Object[] { CommonAuditableEntity.REC_STATUS_VALID, Order.ORDER_FINANCE_STATUS_UNPAY });
		} else {
			return new ArrayList<BankStatement>();
		}
	}

	public Long getNeedAuditCount() {
		Session session = getHibernateTemplate().getSessionFactory().openSession();
		Query query = session.createQuery("select count(*) from " + BankStatement.class.getName() + " where recStatus = ? and status= ?");
		query.setParameter(0, Auditable.REC_STATUS_VALID).setParameter(1, ExpenseApply.STATUS_COMMIT);
		List<Object> result = query.list();
		session.close();
		return (Long) result.get(0);
	}

	public List<Object[]> summary(Integer companyId, Date beginDate, Date endDate) {
		Session session = getHibernateTemplate().getSessionFactory().openSession();
		Query query = session.createQuery("select currency,sum(total) from " + BankStatement.class.getName()
		        + " where recStatus = ? and status = ? and companyId=? and sendDate >= ? and sendDate <= ? group by currency");
		query.setParameter(0, Auditable.REC_STATUS_VALID).setParameter(1, BankStatement.STATUS_APPROVAED).setParameter(2, companyId)
		        .setParameter(3, beginDate).setParameter(4, endDate);
		List<Object[]> result = query.list();
		session.close();
		return result;
	}

	public void find(final PageSearch page) {
		final Integer userId = FrameworkContextUtils.getCurrentUserId();
		getHibernateTemplate().execute(new HibernateCallback<PageSearch>() {
			public PageSearch doInHibernate(Session session) {
				Criteria criteria = HibernateWebUtils.createCriteria(session, page.getEntityClass(), page.getFilters());
				if (page.getFilterValue("EQI_supplierId") == null) {
					if (userId != null) {
						criteria.add(Restrictions.sqlRestriction("company_Id in (select B.company_Id from B_USER_COMPANY B"
						        + " where B.user_id = " + userId + ")"));
					}
				}
				if (0 == page.getTotalCount()) {
					criteria.setProjection(Projections.rowCount());
					Object object = criteria.uniqueResult();
					int total = object == null ? 0 : ((Number) object).intValue();
					page.setTotalCount(total);
				}
				addOrder(page, criteria);
				criteria.setProjection(null);
				List items = criteria.setFirstResult(page.getBegin()).setMaxResults(page.getPageSize()).list();
				page.setList(items);
				return page;
			}
		});
	}

}
